package com.codewsq.java1;

import com.codewsq.entity.MyAnnotation;
import com.codewsq.entity.Person;
import com.codewsq.entity.User;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Arrays;

/**
 * 通过反射获取运行时类的属性
 *
 * @author codewsq
 * @date 2021/7/19 0019 14:15
 */
public class FieldTest {

    @Test
    public void test() {
        Class clazz = Person.class;
        /*
         * getFields():获取运行时类 并包含其父类的所有 public修饰的 属性
         * */
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("\n********************************************\n");
        /*
         *
         * getDeclaredFields():获取运行时类中的所有属性，不包含其父类中声明的属性 ---  常用
         * */
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
    }

    /*
     *
     * 获取 属性的详细信息
     * */
    @Test
    public void test1() throws IllegalAccessException, InstantiationException, InvocationTargetException {
        Class clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            /*
             * 获取权限修饰符
             * */
            int modifiers = field.getModifiers();
            System.out.print(Modifier.toString(modifiers) + "\t");

            /*
             * 获取属性的类型
             * */
            Class<?> type = field.getType();
            System.out.print(type.getName() + "\t");

            /*
             * 变量名
             * */
            String name = field.getName();
            System.out.print(name + ";\t");

            /*
             * 获取属性的注解
             * */
            Annotation[] annotations = field.getAnnotations();
            for (Annotation annotation : annotations) {
                MyAnnotation myAnnotation = (MyAnnotation) annotation;
                String value = myAnnotation.value(); // 获取该注解value()的值
                System.out.print("annotation value：" + value);
            }
            System.out.println();
        }
    }

    /*
     * 使用反射操作运行时类的属性，并给其赋值
     * */
    @Test
    public void test2() throws NoSuchFieldException, IllegalAccessException, InstantiationException {

        Class clazz = Person.class;
        Object obj = clazz.newInstance();

        // 获取指定名称的对象，参数name：将要获取的属性的名称
        // 类似的方法：getField(String name),该方法不常用，因为只能获取public的属性
        Field id = clazz.getDeclaredField("id");
        id.setAccessible(true);

        // set((Object obj,Object value):给属性赋值
        // 参数1：运行时类的对象 参数2：要赋的值
        id.set(obj, 10);

        // get((Object obj):获取属性的值
        // 参数：运行时类的对象，放入的是哪个对象，拿到的就是哪个对象的值
        Object o = id.get(obj);
        System.out.println(o);
    }


    /*
     * 根据field的类型给属性赋予对应的参数
     * */
    @Test
    public void test3() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        Class clazz = User.class;
        Object obj = clazz.newInstance();

        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            // 获取属性的类型
            Type type = field.getGenericType();
            Class<?> aClass = Class.forName(type.getTypeName());
            // 给属性赋值，值为属性的类型实例化的对象，注意：如果属性类型没有提供空参构造器，则会报异常
            field.set(obj, aClass.newInstance());
        }
        User user = (User) obj;
        System.out.println(user);
    }


    /*
     * 根据field的类型给属性赋予对应的参数
     *
     * 新要求：给加了MyAnnntation注解的属性赋值，模拟spring @AutoWrite注解
     * */
    @Test
    public void test4() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        Class clazz = User.class;
        Object obj = clazz.newInstance();

        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            Annotation[] annotations = field.getAnnotations();
            if (annotations == null) {
                continue;
            }
            for (Annotation annotation : annotations) {
                String name = annotation.annotationType().getName();
                if ("com.codewsq.entity.MyAnnotation".equals(name)) {
                    // 获取属性的类型
                    Type type = field.getGenericType();
                    Class<?> aClass = Class.forName(type.getTypeName());
                    // 给属性赋值，值为 属性的类型实例化的对象
                    field.set(obj, aClass.newInstance());
                }
            }
        }
        User user = (User) obj;
        System.out.println(user);
    }

}
